//
//  Lock_DemoVC.swift
//  APSwift
//
//  Created by jianbo.pei on 2023/7/14.
//

import UIKit
import Dispatch

/*:
 ## 初始化
 ```Swift
 public convenience init(label: String,
                         qos: DispatchQoS = .unspecified,
                         attributes: DispatchQueue.Attributes = [],
                         autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit,
                         target: DispatchQueue? = nil)
 ```
 
 ### `label`
 队列标识符，方便在调试工具（如 `Instruments` ，奔溃日志）中找到对应的信息。
 
 ### `qos`
 `QoS` (`Quality of Service`)：服务质量，队列在执行时是有优先级的，优先级越高的队列将获得更多的计算资源。优先级如下：
 > `background` < `utility` < `default` < `userInitiated` < `userInteractive`
 
 ### `attributes`
 与队列关联的属，只要不设置这个属性那么创建的队列就是串行队列。
 - concurrent
 - initiallyInactive
 
 ### `autoreleaseFrequency`
 调度队列自动释放对象的频率。
 - inherit
 - workItem
 - never
 
 ### `target`
 要在其上执行块的目标队列。
 
 ## 参考链接
 - [Swift线程安全详解－概念，三种锁，死锁，Atomic，synchronized](https://blog.csdn.net/hello_hwc/article/details/50037505)
 - [Swift 线程安全数组](https://cloud.tencent.com/developer/article/1006700?from=15425)
 - [iOS GCD学习《二》](https://blog.csdn.net/u013756604/article/details/111224217)
 */

class Lock_DemoVC: UIViewController {
    let tempArray = NSMutableArray()
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        testForUnsafe1()
//        testForSafeArray()
//        testForTargetNil()
//        testForTargetNotNil()
//        testForTargetConcurrent()
    }
}

//!!!: 不是线程安全的
extension Lock_DemoVC {
    func testForUnsafe1() {
        let queue1 = DispatchQueue(label: "com.jianbo.pei.lock.queue1")
        let queue2 = DispatchQueue(label: "com.jianbo.pei.lock.queue2")
        queue1.async {
            for idx in 1...500 {
                debugPrint("testForUnsafe1 tempArray（queue1） is \(self.tempArray)")
                self.tempArray.add(NSNumber(integerLiteral: idx))
            }
        }
        queue2.async {
            for idx in 501...1000 {
                debugPrint("testForUnsafe1 tempArray（queue2） is \(self.tempArray)")
                self.tempArray.add(NSNumber(integerLiteral: idx))
            }
        }
    }
    
    
}

//!!!: 自定义`SafeArray`示例
extension Lock_DemoVC {
    func testForSafeArray() {
        let idxs = SafeArray<Int>()
        DispatchQueue.concurrentPerform(iterations: 1000) { _ in
            let last = idxs.last ?? 0
            idxs.append(last + 1)
        }
        debugPrint("test idxs is \(idxs.count)")
    }
}


//!!!: `DispatchQueue`的`target`示例
extension Lock_DemoVC {
    //MARK: `target`参数为`nil`
    func testForTargetNil() {
        let concurrentQueue1 = DispatchQueue(label: "com.jianbo.pei.lock.concurrent", attributes: .concurrent, target: nil)
        for idx in 0..<10 {
            concurrentQueue1.async {
                debugPrint("targetNil idx is \(idx), 当前线程：\(Thread.current)")
            }
        }
    }
    
    /**
     "targetNil idx is 0, 当前线程：<NSThread: 0x6000034cc840>{number = 7, name = (null)}"
     "targetNil idx is 3, 当前线程：<NSThread: 0x6000034c8c40>{number = 3, name = (null)}"
     "targetNil idx is 2, 当前线程：<NSThread: 0x6000034d0280>{number = 9, name = (null)}"
     "targetNil idx is 5, 当前线程：<NSThread: 0x6000034cc840>{number = 7, name = (null)}"
     "targetNil idx is 4, 当前线程：<NSThread: 0x6000034db080>{number = 5, name = (null)}"
     "targetNil idx is 1, 当前线程：<NSThread: 0x6000034d5040>{number = 8, name = (null)}"
     "targetNil idx is 7, 当前线程：<NSThread: 0x6000034c8c40>{number = 3, name = (null)}"
     "targetNil idx is 6, 当前线程：<NSThread: 0x6000034caa80>{number = 4, name = (null)}"
     "targetNil idx is 8, 当前线程：<NSThread: 0x6000034d0280>{number = 9, name = (null)}"
     "targetNil idx is 9, 当前线程：<NSThread: 0x6000034d5140>{number = 10, name = (null)}"
     */
    
    //MARK: `target`参数为串行队列`serialQueue`
    func testForTargetNotNil() {
        let serialQueue = DispatchQueue(label: "com.jianbo.pei.lock.serial")
        let concurrentQueue2 = DispatchQueue(label: "com.jianbo.pei.lock.concurrent", attributes: .concurrent, target: serialQueue)
        for idx in 0..<10 {
            concurrentQueue2.async {
                debugPrint("TargetNotNil idx is \(idx), 当前线程：\(Thread.current)")
            }
        }
    }
    
    /**
     "TargetNotNil idx is 0, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 1, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 2, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 3, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 4, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 5, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 6, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 7, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 8, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     "TargetNotNil idx is 9, 当前线程：<NSThread: 0x600000e3e700>{number = 7, name = (null)}"
     */
    
    
    //MARK: `target`参数为并发队列`concurrentQueue`
    
    func testForTargetConcurrent() {
        let concurrentQueue = DispatchQueue(label: "com.jianbo.pei.lock.concurrent", attributes: .concurrent)
        let serialQueue1 = DispatchQueue(label: "com.jianbo.pei.lock.serial_1", target: concurrentQueue)
        let serialQueue2 = DispatchQueue(label: "com.jianbo.pei.lock.serial_2", target: concurrentQueue)
        for idx in 0..<10 {
            serialQueue1.async {
                debugPrint("serialQueue1 idx is \(idx), 当前线程：\(Thread.current)")
            }
            serialQueue2.async {
                debugPrint("⭐️ serialQueue2 idx is \(idx), 当前线程：\(Thread.current)")
            }
        }
    }
    
    /**
     "serialQueue1 idx is 0, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "⭐️ serialQueue2 idx is 0, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "serialQueue1 idx is 1, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "⭐️ serialQueue2 idx is 1, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "serialQueue1 idx is 2, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "⭐️ serialQueue2 idx is 2, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "⭐️ serialQueue2 idx is 3, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "⭐️ serialQueue2 idx is 4, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "⭐️ serialQueue2 idx is 5, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "⭐️ serialQueue2 idx is 6, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "serialQueue1 idx is 3, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "⭐️ serialQueue2 idx is 7, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "⭐️ serialQueue2 idx is 8, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "⭐️ serialQueue2 idx is 9, 当前线程：<NSThread: 0x60000185cec0>{number = 9, name = (null)}"
     "serialQueue1 idx is 4, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "serialQueue1 idx is 5, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "serialQueue1 idx is 6, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "serialQueue1 idx is 7, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "serialQueue1 idx is 8, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     "serialQueue1 idx is 9, 当前线程：<NSThread: 0x6000018556c0>{number = 8, name = (null)}"
     
     可以看出，`serialQueue1` 和 `serialQueue2` 是串行队列，它们的 `target` 是并发队列（`concurrentQueue`），这样，`serialQueue1` 和 `serialQueue2` 各自内部依然是串行执行，但`serialQueue1` 和 `serialQueue2` 之间却是并发执行。
     */
    
}


//!!!: `DispatchQueue`初始化
extension Lock_DemoVC {
    
    /// <#Description#>
    /// - Parameters:
    ///   - label: <#label description#>
    ///   - qos: QoS (Quality of Service)，体现在代码上面就是优先级所对应的名称变了
    ///   - attributes: <#attributes description#>
    ///   - autoreleaseFrequency: <#autoreleaseFrequency description#>
    ///   - target: <#target description#>
    public convenience init(label: String,
                            qos: DispatchQoS = .unspecified,
                            attributes: DispatchQueue.Attributes = [],
                            autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit,
                            target: DispatchQueue? = nil) {
        self.init()
    }
}


